#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include "Connection.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include "Log.hpp"

using func_t = std::function<std::string(std::string &)>;
class IOService : public Connection
{
    static const int size = 1024;

public:
    IOService(int sockfd)
    {
        SetNonBlock(sockfd);
        SetSockfd(sockfd);
        SetEvents(EPOLLIN | EPOLLET);
    }
    ~IOService() {}
    virtual void Recver() override
    {
        // 1.读取所有数据
        while (true)
        {
            char buffer[size];
            ssize_t s = recv(SockFd(), buffer, size - 1, 0); // 非阻塞
            if (s > 0)
            {
                // 读取成功了
                buffer[s] = 0;
                AppendString(buffer);
            }
            else if (s == 0)
            {
                // 对端关闭连接
                Excepter();
                return;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    LOG(LogLevel::DEBUG) << "recv all data ... done";
                    break;
                }
                else if (errno == EINTR)
                {
                    LOG(LogLevel::DEBUG) << "recv interrupted by signal ... continue";
                    continue;
                }
                else
                {
                    // 发生错误了
                    Excepter();
                    return;
                }
            }
        }
        // 走到下面，一定把本轮数据读完了
        std::cout << "outbuffer: " << InBuffer() << std::endl;
        // 我们怎么知道，读到了完整的请求呢？ 协议
        std::string result;
        if (_on_message)
            result = _on_message(InBuffer());

        // 添加应答信息
        AppendToOut(result);
        // 如何处理写的问题，变成，outbuffer发送给对方的问题
        if (!IsOutBufferEmpty())
         {
            // 方案1：Sender(); //直接发送，推荐做法
            // 方案2：GetOwner()->EnableReadWrite(SockFd(), true, true); // 开启对写事件关心
         }   
    }
    virtual void Sender() override
    {
        // 直接写
        while (true)
        {
            ssize_t n = send(SockFd(), OutString().c_str(), OutString().size(), 0);
            if(n > 0)
            {
                // 成功
                DisacrdOutString(n);
            }
            else if(n == 0)
            {
                // 缓冲区数据发完
                break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    // 缓冲区写满了，下次再来写
                    break;
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }
        // 走到这里，有两种情况
        // 1，outbuffer empty
        // 2.发送缓冲区写满了，并且 outbuffer没有empty， 写条件不满足，使能sockfd在epoll中的事件
        if(!IsOutBufferEmpty())
        {
            // 修改对sockfd的事件关心 -- 开启对写事件关心
            // 按需设置
            GetOwner()->EnableReadWrite(SockFd(), true, true);
        }
        else
        {
            // 如果缓冲区数据为空了，就关闭写事件监控
            GetOwner()->EnableReadWrite(SockFd(), true, false);
        }
    }
    virtual void Excepter() override
    {
        // IO读取时，所有的异常处理，全部都会转化成为这一个函数的调用
        // 出异常，我们怎么处理 
        // 打印日志，差错处理，关闭连接，Reactor移除connection。从内核中移除对fd的事件监控
        LOG(LogLevel::INFO) << "客户端可能结束，进行异常处理: " << SockFd();
        GetOwner()->DelConnection(SockFd());
    }
    void RegisterOnMessage(func_t on_message)
    {
        _on_message = on_message;
    }

private:
    func_t _on_message;
};